/*
 * Copyright (C) 2010 Fred Barrie This program is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received
 * a copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package org.aergia.vinny.engine;

import java.util.Calendar;
import java.util.Collection;

import org.aergia.vinny.core.ApiResult;
import org.aergia.vinny.core.enums.DayOfWeek;
import org.aergia.vinny.core.enums.TimeFrame;
import org.aergia.vinny.database.Database;
import org.aergia.vinny.database.pojo.Card;
import org.aergia.vinny.database.pojo.Location;
import org.aergia.vinny.database.pojo.OperatingHours;
import org.aergia.vinny.database.pojo.Organization;
import org.aergia.vinny.database.pojo.Scan;
import org.aergia.vinny.database.pojo.Service;
import org.aergia.vinny.database.pojo.ServiceType;
import org.aergia.vinny.database.pojo.Skill;
import org.aergia.vinny.database.pojo.SkillRate;
import org.aergia.vinny.database.pojo.VinnyOption;
import org.aergia.vinny.database.pojo.VinnyRole;
import org.aergia.vinny.database.pojo.VinnyUser;
import org.aergia.vinny.database.pojo.Volunteer;
import org.aergia.vinny.database.pojo.VolunteerGroup;
import org.aergia.vinny.database.pojo.Workstation;

/**
 * @author fred
 */
public interface Engine {

	public static final String DEFAULT_PRODUCT_NAME = "trackin' it!";
	public static final String DEFAULT_SERVICE_OF = "Nevada Volunteers";

	/**
	 * @param cardNumber
	 * @param volunteer
	 * @param user
	 * @return the result of adding a card to a volunteer.
	 */
	ApiResult<Card> addCard(String cardNumber, Volunteer volunteer, Calendar startDate, VinnyUser user);

	/**
	 * Add an unknown generic volunteer for the specified card number.
	 * 
	 * @param cardNumber
	 * @return a generic volunteer for the specified card number.
	 */
	ApiResult<Volunteer> addGenericVolunteer(String cardNumber, Calendar startDate);

	/**
	 * @param groupName
	 * @param user
	 * @return a new group
	 */
	ApiResult<VolunteerGroup> addGroup(String groupName, VinnyUser user);

	/**
	 * @param volunteer
	 * @param date
	 * @param duration
	 * @param timeFrame
	 * @param serviceType
	 * @param user
	 * @return the result of adding a service
	 */
	ApiResult<Service> addService(Volunteer volunteer, Calendar date, int duration, TimeFrame timeFrame, ServiceType serviceType, VinnyUser user);

	/**
	 * @param name
	 * @param user
	 * @return api result of adding the service type
	 */
	ApiResult<ServiceType> addServiceType(String name, VinnyUser user);

	/**
	 * @param skill
	 * @param rate
	 * @param user
	 * @return the result of adding a new skill
	 */
	ApiResult<Skill> addSkill(Skill skill, SkillRate rate, VinnyUser user);

	/**
	 * @param skill
	 * @param rate
	 * @param user
	 * @return the result of adding a new skill rate
	 */
	ApiResult<SkillRate> addSkillRate(Skill skill, SkillRate rate, VinnyUser user);

	/**
	 * @param volunteer
	 * @param skill
	 * @param user
	 * @return result of add skill to volunteer
	 */
	ApiResult<Volunteer> addSkillToVolunteer(Volunteer volunteer, Skill skill, VinnyUser user);

	/**
	 * @param newUser
	 * @param user
	 * @return
	 */
	ApiResult<VinnyUser> addUser(VinnyUser newUser, VinnyUser user);

	/**
	 * @param firstName
	 * @param lastName
	 * @param startDate
	 * @param user
	 * @return api result with the volunteer if successful
	 */
	ApiResult<Volunteer> addVolunteer(String firstName, String lastName, VinnyUser user);

	/**
	 * @param name
	 * @param user
	 * @return api result of adding the workstation
	 */
	ApiResult<Workstation> addWorkstation(String name, VinnyUser user);

	/**
	 * Authorizes all services by the admin user.
	 * 
	 * @return success or failure
	 */
	ApiResult<?> authorizeAllServices();

	/**
	 * Authorizes services by the specified user.
	 * 
	 * @param services
	 * @param user
	 * @return success or failure
	 */
	ApiResult<?> authorizeServices(Collection<? extends Service> services, VinnyUser user);

	/**
	 * Calculate service records from the scans.
	 */
	void calculateService();

	/**
	 * @param newHours
	 * @param user
	 * @return result of changing the operating hours
	 */
	ApiResult<OperatingHours> changeOperatingHours(OperatingHours newHours, VinnyUser user);

	/**
	 * Deny services by the specified user.
	 * 
	 * @param services
	 * @param user
	 * @return success or failure
	 */
	ApiResult<?> denyServices(Collection<Service> services, VinnyUser user);

	ApiResult<Card> getCard(String cardNumber);

	/**
	 * @return list of cards, it maybe empty
	 */
	Collection<? extends Card> getCards();

	Database getDatabase();

	/**
	 * @return the first location
	 */
	Location getFirstLocation();

	/**
	 * @param groupName
	 * @param location
	 */
	ApiResult<VolunteerGroup> getGroup(String groupName);

	/**
	 * @return all the defined groups
	 */
	Collection<? extends VolunteerGroup> getGroups();

	OperatingHours getHours(DayOfWeek day);

	/**
	 * @param id
	 * @return location
	 */
	ApiResult<Location> getLocation(int id);

	/**
	 * @param parameterName
	 * @param defaultValue
	 * @return the option or defaultValue if not set
	 */
	String getOption(String parameterName, String defaultValue);

	Collection<? extends VinnyOption> getOptions();

	ApiResult<VinnyRole> getRole(String permission);

	/**
	 * @return collection of defined roles
	 */
	Collection<? extends VinnyRole> getRoles();

	/**
	 * @return list of scans, it maybe empty
	 */
	Collection<? extends Scan> getScans();

	/**
	 * @return the list of services
	 */
	Collection<? extends Service> getServices();

	/**
	 * @param name
	 * @return the specified service type or an error
	 */
	ApiResult<ServiceType> getServiceType(String name);

	/**
	 * @return list of service types
	 */
	Collection<? extends ServiceType> getServiceTypes();

	/**
	 * @param skillName
	 * @return the result of looking up the skill
	 */
	ApiResult<Skill> getSkill(String skillName);

	/**
	 * @return a collection of users
	 */
	Collection<? extends VinnyUser> getUsers();

	Collection<VinnyUser> getUsers(String inRole);

	/**
	 * Get the volunteer with the scanned card number.
	 * 
	 * @param scanned
	 * @return the volunteer with this scanned card number or NULL
	 */
	ApiResult<Volunteer> getVolunteer(String scanned);

	/**
	 * @return list of volunteers can be empty
	 */
	Collection<? extends Volunteer> getVolunteers();

	/**
	 * @param id
	 * @return the specified workstation or an error
	 */
	ApiResult<Workstation> getWorkstation(int id);

	/**
	 * @return list of workstation for this location
	 */
	Collection<? extends Workstation> getWorkstations();

	/**
	 * @param organization
	 * @param location
	 * @param hours
	 * @param rate
	 * @param date
	 * @return
	 */
	ApiResult<Location> installLocation(Organization organization, Location location, Collection<OperatingHours> hours, int rate, Calendar date);

	/**
	 * @param hostName
	 */
	ApiResult<Workstation> installWorkstation(String hostName);

	/**
	 * @param cardNumber
	 * @return is card available
	 */
	ApiResult<Card> isCardAvailable(Volunteer volunteer, String cardNumber);

	/**
	 * @return if the database is initialized
	 */
	boolean isDatabaseInitialized();

	/**
	 * Determine if the day and hour is in the operating hours for this
	 * location.
	 * 
	 * @param day
	 * @param hour
	 * @return true if the day and hour is in the operating hours
	 */
	boolean isInOperatingHours(DayOfWeek day, int hour);

	/**
	 * @param userName
	 * @return true if the user name already used
	 */
	boolean isUserNameInUse(String userName);

	/**
	 * Determine if the scanned string is a vinny card.
	 * 
	 * @param scanned
	 * @return true if the scanned string is a vinny card.
	 */
	boolean isVinnyCard(String scanned);

	/**
	 * @param volunteer
	 * @param user
	 * @return the result of modifying a volunteer.
	 */
	ApiResult<Volunteer> modifyVolunteer(Volunteer volunteer, VinnyUser user);

	/**
	 * @param group
	 * @param user
	 * @return the result of deleting the group
	 */
	ApiResult<VolunteerGroup> removeGroup(VolunteerGroup group, VinnyUser user);

	/**
	 * @param serviceType
	 * @param user
	 * @return
	 */
	ApiResult<ServiceType> removeServiceType(ServiceType serviceType, VinnyUser user);

	/**
	 * Remove a skill from a volunteer.
	 * 
	 * @param volunteer
	 * @param skill
	 * @param user
	 */
	ApiResult<Volunteer> removeSkillFromVolunteer(Volunteer volunteer, Skill skill, VinnyUser user);

	/**
	 * 
	 */
	ApiResult<VinnyUser> removeUser(VinnyUser removeUser, VinnyUser user);

	/**
	 * @param volunteer
	 * @param user
	 * @return the result of removing a volunteer.
	 */
	ApiResult<Volunteer> removeVolunteer(Volunteer volunteer, VinnyUser user);

	/**
	 * @param workstation
	 * @param user
	 * @return
	 */
	ApiResult<Workstation> removeWorkstation(Workstation workstation, VinnyUser user);

	/**
	 * @param card
	 * @param user
	 * @return the result of saving the card
	 */
	ApiResult<Card> saveCard(Card card, VinnyUser user);

	ApiResult<VolunteerGroup> saveGroup(VolunteerGroup group, VinnyUser user);

	/**
	 * @param hours
	 * @param user
	 * @return the result of saving the operating hours
	 */
	ApiResult<OperatingHours> saveHours(OperatingHours hours, VinnyUser user);

	ApiResult<VinnyOption> saveOption(VinnyOption option, VinnyUser user);

	/**
	 * @param scan
	 * @param user
	 * @return result of saving the scan
	 */
	ApiResult<Scan> saveScan(Scan scan, VinnyUser user);

	ApiResult<Service> saveService(Service service, VinnyUser user);

	/**
	 * @param serviceType
	 * @return the result of saving the serviceType
	 */
	ApiResult<ServiceType> saveServiceType(ServiceType serviceType, VinnyUser user);

	/**
	 * 
	 */
	ApiResult<VinnyUser> saveUser(VinnyUser saveUser, VinnyUser user);

	/**
	 * @param volunteer
	 * @return the result of saving a volunteer
	 */
	ApiResult<Volunteer> saveVolunteer(Volunteer volunteer, VinnyUser user);

	/**
	 * @param workstation
	 * @return the result of saving the workstation
	 */
	ApiResult<Workstation> saveWorkstation(Workstation workstation, VinnyUser user);

	/**
	 * @param volunteer
	 * @param skill
	 * @param date
	 * @return result of scanning the card
	 */
	ApiResult<Scan> scanCard(String card, Calendar date);

	void setLocation(Location location);

	/**
	 * @param parameterName
	 * @param value
	 */
	void setOption(String parameterName, String value);

	/**
	 * @param workstation
	 */
	void setWorkstation(final Workstation workstation);

	/**
	 * @param oldCard
	 * @param newCard
	 * @return the result of switching cards
	 */
	ApiResult<Card> switchCard(Card oldCard, Card newCard);

	/**
	 * Validate the user using the supplied password.
	 * 
	 * @param userName
	 * @param password
	 * @return a VinnyUser or null if userName is unknown or invalid password.
	 */
	ApiResult<VinnyUser> validateUser(String userName, String password);
}
